home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 7
/
Amiga Format AFCD07 (Dec 1996, Issue 91).iso
/
serious
/
shareware
/
programming
/
aros
/
filesys
/
ramdev.c
< prev
Wrap
C/C++ Source or Header
|
1996-09-12
|
33KB
|
1,298 lines
/*
(C) 1995-96 AROS - The Amiga Replacement OS
$Id: ramdev.c,v 1.2 1996/08/01 17:41:23 digulla Exp $
$Log: ramdev.c,v $
Revision 1.2 1996/08/01 17:41:23 digulla
Added standard header for all files
Desc:
Lang:
*/
#include <exec/errors.h>
#include <exec/types.h>
#include <exec/resident.h>
#include <exec/memory.h>
#include <exec/semaphores.h>
#include <clib/exec_protos.h>
#include <utility/tagitem.h>
#include <clib/utility_protos.h>
#include <dos/dosextens.h>
#include <dos/dosasl.h>
#include <dos/filesystem.h>
#include <clib/dos_protos.h>
#include <aros/libcall.h>
#ifdef __GNUC__
#include "ramdev_gcc.h"
#endif
#define NEWLIST(l) \
((l)->lh_Head=(struct Node *)&(l)->lh_Tail, \
(l)->lh_Tail=NULL, \
(l)->lh_TailPred=(struct Node *)(l))
extern const char name[];
extern const char version[];
extern const APTR inittabl[4];
extern void *const functable[];
extern const UBYTE datatable;
extern struct rambase *ramdev_init();
extern void ramdev_open();
extern BPTR ramdev_close();
extern BPTR ramdev_expunge();
extern int ramdev_null();
extern void ramdev_beginio();
extern LONG ramdev_abortio();
extern void deventry();
extern const char end;
/* Device node */
struct cnode
{
struct MinNode node;
LONG type; /* ST_LINKDIR */
char *name; /* Link's name */
struct cnode *self; /* Pointer to top of structure */
struct hnode *link; /* NULL */
LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
ULONG protect; /* 0 */
char *comment; /* NULL */
struct vnode *volume; /* Pointer to volume */
struct DosList *doslist; /* Pointer to doslist entry */
};
/* Volume node */
struct vnode
{
struct MinNode node;
LONG type; /* ST_USERDIR */
char *name; /* Directory name */
struct vnode *self; /* Points to top of structure */
struct hnode *link; /* This one is linked to me */
LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
ULONG protect; /* 0 */
char *comment; /* NULL */
struct MinList list; /* Contents of directory */
struct MinList waiting; /* IORequests waiting on dismountage */
ULONG volcount; /* number of handles on this volume */
struct DosList *doslist; /* Pointer to doslist entry */
};
/* Directory node */
struct dnode
{
struct MinNode node;
LONG type; /* ST_USERDIR */
char *name; /* Directory name */
struct vnode *volume; /* Volume's root directory */
struct hnode *link; /* This one is linked to me */
LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
ULONG protect; /* protection bits */
char *comment; /* Some comment */
struct MinList list; /* Contents of directory */
};
/* File node */
struct fnode
{
struct MinNode node;
LONG type; /* ST_FILE */
char *name; /* Filename */
struct vnode *volume; /* Volume's root directory */
struct hnode *link; /* This one is linked to me */
LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
ULONG protect; /* protection bits */
char *comment; /* Some file comment */
LONG size; /* Filesize */
UBYTE *blocks[16]; /* Upto 0x1000 bytes */
UBYTE **iblocks[4]; /* Upto 0x41000 bytes */
UBYTE ***i2block; /* Upto 0x1041000 bytes */
UBYTE ****i3block; /* Upto 0x101041000 bytes */
};
/* Softlink node */
struct snode
{
struct MinNode node;
LONG type; /* ST_SOFTLINK */
char *name; /* Link's name */
struct vnode *volume; /* Volume's root directory */
struct hnode *link; /* This one is hardlinked to me */
LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
ULONG protect; /* protection bits */
char *comment; /* Some file comment */
char *contents; /* Contents of soft link */
};
/* Hardlink node */
struct hnode
{
struct MinNode node;
LONG type; /* ST_LINKDIR */
char *name; /* Link's name */
struct vnode *volume; /* Volume's root directory */
struct hnode *link; /* This one is hardlinked to me */
LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
ULONG protect; /* protection bits */
char *comment; /* Some file comment */
struct hnode *orig; /* original object */
};
#define BLOCKSIZE 256
#define PBLOCKSIZE (256*sizeof(UBYTE *))
struct filehandle
{
struct dnode *node;
ULONG position;
};
int entry(void)
{
/* If the device was executed by accident return error code. */
return -1;
}
const struct Resident resident=
{
RTC_MATCHWORD,
(struct Resident *)&resident,
(APTR)&end,
RTF_AUTOINIT,
1,
NT_LIBRARY,
0,
(char *)name,
(char *)&version[6],
(ULONG *)inittabl
};
const char name[]="ram.handler";
const char version[]="$VER: ram handler 1.0 (28.3.96)\n\015";
const APTR inittabl[4]=
{
(APTR)sizeof(struct rambase),
(APTR)functable,
(APTR)&datatable,
&ramdev_init
};
void *const functable[]=
{
&ramdev_open,
&ramdev_close,
&ramdev_expunge,
&ramdev_null,
&ramdev_beginio,
&ramdev_abortio,
(void *)-1
};
const UBYTE datatable=0;
__AROS_LH2(struct rambase *, init,
__AROS_LA(struct rambase *, rambase, D0),
__AROS_LA(BPTR, segList, A0),
struct ExecBase *, SysBase, 0, ramdev)
{
__AROS_FUNC_INIT
/* This function is single-threaded by exec by calling Forbid. */
struct MsgPort *port;
struct Task *task;
struct SignalSemaphore *semaphore;
APTR stack;
/* Store arguments */
rambase->sysbase=SysBase;
rambase->seglist=segList;
rambase->dosbase=(struct DosLibrary *)OpenLibrary("dos.library",39);
if(rambase->dosbase!=NULL)
{
rambase->utilitybase=(struct UtilityBase *)OpenLibrary("utility.library",39);
if(rambase->utilitybase!=NULL)
{
port=(struct MsgPort *)AllocMem(sizeof(struct MsgPort),MEMF_PUBLIC|MEMF_CLEAR);
if(port!=NULL)
{
rambase->port=port;
NEWLIST(&port->mp_MsgList);
port->mp_Node.ln_Type=NT_MSGPORT;
port->mp_SigBit=SIGF_SINGLE;
task=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
if(task!=NULL)
{
port->mp_SigTask=task;
port->mp_Flags=PA_IGNORE;
NEWLIST(&task->tc_MemEntry);
task->tc_Node.ln_Type=NT_TASK;
task->tc_Node.ln_Name="ram.handler task";
stack=AllocMem(2048,MEMF_PUBLIC);
if(stack!=NULL)
{
task->tc_SPLower=stack;
task->tc_SPUpper=(BYTE *)stack+2048;
#if STACK_GROWS_DOWNWARDS
task->tc_SPReg=(BYTE *)task->tc_SPUpper-SP_OFFSET-sizeof(APTR);
((APTR *)task->tc_SPUpper)[-1]=rambase;
#else
task->tc_SPReg=(BYTE *)task->tc_SPLower-SP_OFFSET+sizeof(APTR);
*(APTR *)task->tc_SPLower=rambase;
#endif
semaphore=(struct SignalSemaphore *)AllocMem(sizeof(struct SignalSemaphore),MEMF_PUBLIC|MEMF_CLEAR);
if(semaphore!=NULL)
{
rambase->sigsem=semaphore;
InitSemaphore(semaphore);
if(AddTask(task,deventry,NULL)!=NULL)
return rambase;
FreeMem(semaphore,sizeof(struct SignalSemaphore));
}
FreeMem(stack,2048);
}
FreeMem(task,sizeof(struct Task));
}
FreeMem(port,sizeof(struct MsgPort));
}
CloseLibrary((struct Library *)rambase->utilitybase);
}
CloseLibrary((struct Library *)rambase->dosbase);
}
return NULL;
__AROS_FUNC_EXIT
}
/* Use This from now on */
#ifdef SysBase
#undef SysBase
#endif
#ifdef DOSBase
#undef DOSBase
#endif
#ifdef UtilityBase
#undef UtilityBase
#endif
#define SysBase rambase->sysbase
#define DOSBase rambase->dosbase
#define UtilityBase rambase->utilitybase
__AROS_LH3(void, open,
__AROS_LA(struct IOFileSys *, iofs, A1),
__AROS_LA(ULONG, unitnum, D0),
__AROS_LA(ULONG, flags, D0),
struct rambase *, rambase, 1, ramdev)
{
__AROS_FUNC_INIT
/*
This function is single-threaded by exec by calling Forbid.
If you break the Forbid() another task may enter this function
at the same time. Take care.
*/
/* Keep compiler happy */
unitnum=0;
flags=0;
/* I have one more opener. */
rambase->device.dd_Library.lib_OpenCnt++;
rambase->device.dd_Library.lib_Flags&=~LIBF_DELEXP;
/* Set returncode */
iofs->IOFS.io_Error=0;
/* Mark Message as recently used. */
iofs->IOFS.io_Message.mn_Node.ln_Type=NT_REPLYMSG;
__AROS_FUNC_EXIT
}
__AROS_LH1(BPTR, close,
__AROS_LA(struct IOFileSys *, iofs, A1),
struct rambase *, rambase, 2, ramdev)
{
__AROS_FUNC_INIT
/*
This function is single-threaded by exec by calling Forbid.
If you break the Forbid() another task may enter this function
at the same time. Take care.
*/
/* Let any following attemps to use the device crash hard. */
iofs->IOFS.io_Device=(struct Device *)-1;
/* I have one fewer opener. */
if(!--rambase->device.dd_Library.lib_OpenCnt)
{
/* Delayed expunge pending? */
if(rambase->device.dd_Library.lib_Flags&LIBF_DELEXP)
/* Then expunge the device */
return expunge();
}
return 0;
__AROS_FUNC_EXIT
}
__AROS_LH0(BPTR, expunge, struct rambase *, rambase, 3, ramdev)
{
__AROS_FUNC_INIT
BPTR ret;
/*
This function is single-threaded by exec by calling Forbid.
Never break the Forbid() or strange things might happen.
*/
/* Test for openers. */
if(rambase->device.dd_Library.lib_OpenCnt)
{
/* Set the delayed expunge flag and return. */
rambase->device.dd_Library.lib_Flags|=LIBF_DELEXP;
return 0;
}
/* Kill device task and free all resources */
RemTask(rambase->port->mp_SigTask);
FreeMem(rambase->sigsem,sizeof(struct SignalSemaphore));
FreeMem(((struct Task *)rambase->port->mp_SigTask)->tc_SPLower,2048);
FreeMem(rambase->port->mp_SigTask,sizeof(struct Task));
FreeMem(rambase->port,sizeof(struct MsgPort));
CloseLibrary((struct Library *)rambase->utilitybase);
CloseLibrary((struct Library *)rambase->dosbase);
/* Get rid of the device. Remove it from the list. */
Remove(&rambase->device.dd_Library.lib_Node);
/* Get returncode here - FreeMem() will destroy the field. */
ret=rambase->seglist;
/* Free the memory. */
FreeMem((char *)rambase-rambase->device.dd_Library.lib_NegSize,
rambase->device.dd_Library.lib_NegSize+rambase->device.dd_Library.lib_PosSize);
return ret;
__AROS_FUNC_EXIT
}
__AROS_LH0I(int, null, struct rambase *, rambase, 4, ramdev)
{
__AROS_FUNC_INIT
return 0;
__AROS_FUNC_EXIT
}
__AROS_LH1(void, beginio,
__AROS_LA(struct IOFileSys *, iofs, A1),
struct rambase *, rambase, 5, ramdev)
{
__AROS_FUNC_INIT
/* WaitIO will look into this */
iofs->IOFS.io_Message.mn_Node.ln_Type=NT_MESSAGE;
/* Nothing is done quick */
iofs->IOFS.io_Flags&=~IOF_QUICK;
/* So let the device task do it */
PutMsg(rambase->port,&iofs->IOFS.io_Message);
__AROS_FUNC_EXIT
}
__AROS_LH1(LONG, abortio,
__AROS_LA(struct IOFileSys *, iofs, A1),
struct rambase *, rambase, 6, ramdev)
{
__AROS_FUNC_INIT
#if 0
if(iofs->IOFS.io_Command==FSA_NOTIFY)
{
ObtainSemaphore(rambase->sigsem);
rambase->iofs=iofs;
Signal(rambase->port->mp_SigTask,rambase->port->mp_SigBit);
while(rambase->iofs!=NULL)
Wait(1<<iofs->IOFS.io_Message.mn_ReplyPort->mp_SigBit);
ReleaseSemaphore(rambase->sigsem);
}
#endif
return 0;
__AROS_FUNC_EXIT
}
static STRPTR Strdup(struct rambase *rambase, STRPTR string)
{
STRPTR s2=string,s3;
while(*s2++)
;
s3=(STRPTR)AllocMem(s2-string,MEMF_ANY);
if(s3!=NULL)
CopyMem(string,s3,s2-string);
return s3;
}
static void Strfree(struct rambase *rambase, STRPTR string)
{
STRPTR s2=string;
if(string==NULL)
return;
while(*s2++)
;
FreeMem(string,s2-string);
}
static LONG startup(struct rambase *rambase, STRPTR name, struct TagItem *args)
{
struct filehandle *fhv, *fhc;
struct DosList *dlv, *dlc;
struct cnode *dev;
struct vnode *vol;
/* Get compiler happy */
args=NULL;
fhv=(struct filehandle*)AllocMem(sizeof(struct filehandle),MEMF_CLEAR);
if(fhv!=NULL)
{
vol=(struct vnode *)AllocMem(sizeof(struct vnode),MEMF_CLEAR);
if(vol!=NULL)
{
vol->name=Strdup(rambase,"Ram Disk");
if(vol->name!=NULL)
{
dlv=MakeDosEntry("Ram Disk",DLT_VOLUME);
if(dlv!=NULL)
{
fhc=(struct filehandle *)AllocMem(sizeof(struct filehandle),MEMF_CLEAR);
if(fhc!=NULL)
{
dev=(struct cnode *)AllocMem(sizeof(struct cnode),MEMF_CLEAR);
if(dev!=NULL)
{
dev->name=Strdup(rambase,name);
if(dev->name!=NULL)
{
dlc=MakeDosEntry(name,DLT_DEVICE);
if(dlc!=NULL)
{
vol->type=ST_USERDIR;
vol->self=vol;
vol->doslist=dlv;
NEWLIST((struct List *)&vol->list);
fhv->node=(struct dnode *)vol;
dlv->dol_Unit =(struct Unit *)fhv;
dlv->dol_Device=&rambase->device;
dev->type=ST_LINKDIR;
dev->self=dev;
dev->volume=vol;
dev->doslist=dlc;
fhc->node=(struct dnode *)dev;
dlc->dol_Unit =(struct Unit *)fhc;
dlc->dol_Device=&rambase->device;
if(AddDosEntry(dlv))
{
if(AddDosEntry(dlc))
{
rambase->unitcount++;
return 0;
}
RemDosEntry(dlv);
}
FreeDosEntry(dlc);
}
Strfree(rambase,dev->name);
}
FreeMem(dev,sizeof(struct cnode));
}
FreeMem(fhc,sizeof(struct filehandle));
}
FreeDosEntry(dlv);
}
Strfree(rambase,vol->name);
}
FreeMem(vol,sizeof(struct vnode));
}
FreeMem(fhv,sizeof(struct filehandle));
}
return ERROR_NO_FREE_STORE;
}
static LONG getblock(struct rambase *rambase, struct fnode *file, LONG block, int mode, UBYTE **result)
{
ULONG a, i;
UBYTE **p, **p2;
if(block<0x10)
{
p=&file->blocks[block];
block=0;
i=0;
}else if(block<0x410)
{
block-=0x10;
p=(UBYTE **)&file->iblocks[block/0x100];
block&=0xff;
i=1;
}else if(block<0x10410)
{
block-=0x410;
p=(UBYTE **)&file->i2block;
i=2;
}else
{
block-=0x10410;
p=(UBYTE **)&file->i3block;
i=3;
}
switch(mode)
{
case -1:
p2=(UBYTE **)*p;
if(!block)
*p=NULL;
p=p2;
while(i--&&p!=NULL)
{
a=(block>>i*8)&0xff;
p2=(UBYTE **)p[a];
if(!(block&((1<<i*8)-1)))
{
p[a]=NULL;
if(!a)
FreeMem(p,PBLOCKSIZE);
}
p=p2;
}
if(p!=NULL)
FreeMem(p,BLOCKSIZE);
break;
case 0:
p=(UBYTE **)*p;
while(i--&&p!=NULL)
p=((UBYTE ***)p)[(block>>i*8)&0xff];
*result=(UBYTE *)p;
break;
case 1:
while(i--)
{
if(*p==NULL)
{
*p=AllocMem(PBLOCKSIZE,MEMF_ANY);
if(*p==NULL)
return ERROR_NO_FREE_STORE;
}
p=(UBYTE **)*p+((block>>i*8)&0xff);
}
if(*p==NULL)
{
*p=AllocMem(BLOCKSIZE,MEMF_CLEAR);
if(*p==NULL)
return ERROR_NO_FREE_STORE;
}
*result=*p;
break;
}
return 0;
}
static void zerofill(UBYTE *address, ULONG size)
{
while(size--)
*address++=0;
}
static void shrinkfile(struct rambase *rambase, struct fnode *file, LONG size)
{
ULONG blocks, block;
UBYTE *p;
blocks=(size+BLOCKSIZE-1)/BLOCKSIZE;
block =(file->size+BLOCKSIZE-1)/BLOCKSIZE;
for(;block-->blocks;)
(void)getblock(rambase,file,block,-1,&p);
if(size&0xff)
{
(void)getblock(rambase,file,size,0,&p);
if(p!=NULL)
zerofill(p+(size&0xff),-size&0xff);
}
file->size=size;
}
static void delete(struct rambase *rambase, struct fnode *file)
{
struct hnode *link;
if(file->type!=ST_LINKDIR&&file->link!=NULL)
{
link=file->link;
Strfree(rambase,file->name);
Strfree(rambase,file->comment);
file->name=link->name;
file->link=link->link;
file->usecount=link->usecount;
file->protect=link->protect;
file->comment=link->comment;
Remove((struct Node *)file);
Insert(NULL,(struct Node *)file,(struct Node *)link);
Remove((struct Node *)link);
FreeMem(link,sizeof(struct hnode));
return;
}
Remove((struct Node *)file);
Strfree(rambase,file->name);
Strfree(rambase,file->comment);
switch(file->type)
{
case ST_USERDIR:
FreeMem(file,sizeof(struct dnode));
return;
case ST_FILE:
shrinkfile(rambase,file,0);
FreeMem(file,sizeof(struct fnode));
return;
case ST_LINKDIR:
link=((struct hnode *)file)->orig;
while((struct fnode *)link->link!=file)
link=link->link;
link->link=file->link;
FreeMem(file,sizeof(struct hnode));
return;
case ST_SOFTLINK:
Strfree(rambase,((struct snode *)file)->contents);
return;
}
}
static int fstrcmp(char *s1, char *s2)
{
for(;;)
{
if(ToLower(*s1)!=ToLower(*s2))
return *s1||*s2!='/';
if(!*s1)
return 0;
s1++; s2++;
}
}
static LONG findname(STRPTR *name, struct dnode **dnode)
{
struct dnode *cur=*dnode;
char *rest=*name;
for(;;)
{
if(cur->type==ST_LINKDIR)
cur=(struct dnode *)((struct hnode *)cur)->orig;
if(!*rest)
break;
if(*rest=='/')
{
if((struct dnode *)cur->volume==cur)
return ERROR_OBJECT_NOT_FOUND;
while(cur->node.mln_Pred!=NULL)
cur=(struct dnode *)cur->node.mln_Pred;
cur=(struct dnode *)((BYTE *)cur-offsetof(struct dnode,list));
}else
{
if(cur->type==ST_SOFTLINK)
{
*dnode=cur;
*name=rest;
return ERROR_IS_SOFT_LINK;
}
if(cur->type!=ST_USERDIR)
return ERROR_DIR_NOT_FOUND;
cur=(struct dnode *)cur->list.mlh_Head;
for(;;)
{
if(cur->node.mln_Succ==NULL)
return ERROR_OBJECT_NOT_FOUND;
if(fstrcmp(cur->name,rest))
break;
cur=(struct dnode *)cur->node.mln_Succ;
}
}
while(*rest)
if(*rest++=='/')
break;
}
*dnode=cur;
return 0;
}
static LONG set_file_size(struct rambase *rambase, struct filehandle *handle, LONG *offset, LONG mode)
{
struct fnode *file=(struct fnode *)handle->node;
LONG size=*offset;
if(file->type!=ST_FILE)
return ERROR_OBJECT_WRONG_TYPE;
switch(mode)
{
case OFFSET_BEGINNING: break;
case OFFSET_CURRENT: size+=handle->position; break;
case OFFSET_END: size+=file->size; break;
default: return ERROR_NOT_IMPLEMENTED;
}
if(size<0)
return ERROR_SEEK_ERROR;
if(size<file->size)
shrinkfile(rambase,file,size);
file->size=*offset=size;
return 0;
}
static LONG read(struct rambase *rambase, struct filehandle *handle, APTR buffer, LONG *numbytes)
{
struct fnode *file=(struct fnode *)handle->node;
ULONG num =*numbytes;
ULONG size=file->size;
ULONG block, offset;
UBYTE *buf=buffer, *p;
if(handle->position>=size)
num=0;
else if(handle->position+num>size)
num=size-handle->position;
block =handle->position/BLOCKSIZE;
offset=handle->position&(BLOCKSIZE-1);
size =BLOCKSIZE-offset;
while(num)
{
if(size>num)
size=num;
(void)getblock(rambase,file,block,0,&p);
if(p!=NULL)
CopyMem(p+offset,buffer,size);
else
zerofill(buffer,size);
buffer+=size;
num -=size;
block++;
offset=0;
size=BLOCKSIZE;
}
*numbytes=(UBYTE *)buffer-buf;
handle->position+=*numbytes;
return 0;
}
static LONG write(struct rambase *rambase, struct filehandle *handle, UBYTE *buffer, LONG *numbytes)
{
struct fnode *file=(struct fnode *)handle->node;
ULONG num =*numbytes;
ULONG size=file->size;
ULONG block, offset;
UBYTE *buf=buffer, *p;
LONG error=0;
if(handle->position+num<0)
return ERROR_OBJECT_TOO_LARGE;
block =handle->position/BLOCKSIZE;
offset=handle->position&(BLOCKSIZE-1);
size =BLOCKSIZE-offset;
while(num)
{
if(size>num)
size=num;
error=getblock(rambase,file,block,1,&p);
if(error)
break;
CopyMem(buffer,p+offset,size);
buffer+=size;
num -=size;
block++;
offset=0;
size=BLOCKSIZE;
}
*numbytes=(UBYTE *)buffer-buf;
handle->position+=*numbytes;
if(*numbytes)
return 0;
return error;
}
static LONG locate_object(struct rambase *rambase, struct filehandle **handle, STRPTR name, ULONG mode)
{
struct dnode *dir=(*handle)->node;
struct filehandle *fh;
LONG error;
error=findname(&name,&dir);
if((mode&LMF_CREATE)&&error==ERROR_OBJECT_NOT_FOUND)
{
char *s=name;
struct fnode *file;
while(*s)
if(*s=='/')
return error;
fh=AllocMem(sizeof(struct filehandle),MEMF_CLEAR);
if(fh!=NULL)
{
file=(struct fnode *)AllocMem(sizeof(struct fnode),MEMF_CLEAR);
if(file!=NULL)
{
file->name=Strdup(rambase,name);
if(file->name!=NULL)
{
file->type=ST_FILE;
file->protect=FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE;
file->volume=dir->volume;
file->volume->volcount++;
if(mode&LMF_LOCK)
file->usecount=~0ul/2+1;
file->usecount++;
AddTail((struct List *)&dir->list,(struct Node *)file);
fh->node=(struct dnode *)file;
*handle=fh;
return 0;
}
FreeMem(file,sizeof(struct fnode));
}
FreeMem(fh,sizeof(struct filehandle));
}
return ERROR_NO_FREE_STORE;
}
if(error)
return error;
if((mode&LMF_EXECUTE)&&!(dir->protect&LMF_EXECUTE))
return ERROR_NOT_EXECUTABLE;
if((mode&LMF_WRITE)&&!(dir->protect&LMF_WRITE))
return ERROR_WRITE_PROTECTED;
if((mode&LMF_READ)&&!(dir->protect&LMF_READ))
return ERROR_READ_PROTECTED;
if((mode&LMF_FILE)&&dir->type!=ST_FILE)
return ERROR_OBJECT_WRONG_TYPE;
if(mode&LMF_LOCK)
{
if(dir->usecount)
return ERROR_OBJECT_IN_USE;
dir->usecount=~0ul/2+1;
}else
if(dir->usecount<0)
return ERROR_OBJECT_IN_USE;
dir->usecount++;
fh=(struct filehandle *)AllocMem(sizeof(struct filehandle),MEMF_CLEAR);
if(fh==NULL)
{
dir->usecount=(dir->usecount-1)&~0ul/2;
return ERROR_NO_FREE_STORE;
}
if(mode&LMF_CLEAR)
shrinkfile(rambase,(struct fnode *)dir,0);
dir->volume->volcount++;
fh->node=dir;
*handle=fh;
return 0;
}
static LONG free_lock(struct rambase *rambase, struct filehandle *filehandle)
{
struct dnode *dnode=filehandle->node;
dnode->usecount=(dnode->usecount-1)&~0ul/2;
FreeMem(filehandle,sizeof(struct filehandle));
dnode->volume->volcount--;
return 0;
}
static LONG seek(struct rambase *rambase, struct filehandle *filehandle, LONG *posh, LONG *posl, LONG mode)
{
struct fnode *file=(struct fnode *)filehandle->node;
LONG pos=*posl;
if((pos<0?-1:0)!=*posh)
return ERROR_SEEK_ERROR;
if(file->type!=ST_FILE)
return ERROR_OBJECT_WRONG_TYPE;
switch(mode)
{
case OFFSET_BEGINNING: break;
case OFFSET_CURRENT: pos+=filehandle->position; break;
case OFFSET_END: pos+=file->size; break;
default: return ERROR_NOT_IMPLEMENTED;
}
if(pos<0)
return ERROR_SEEK_ERROR;
*posh=0;
*posl=filehandle->position;
filehandle->position=pos;
return 0;
}
#if 0
static LONG examine_node(struct fnode *file, ULONG **buffer, ULONG *size, ULONG type, ULONG namesize, ULONG commsize)
{
ULONG *buf=*buffer;
ULONG siz=*size/sizeof(ULONG),bsize;
STRPTR s1=NULL, s2;
int i, k;
for(i=1;type;i++)
{
if(type&1)
{
if(!siz)
return ERROR_BUFFER_OVERFLOW;
switch(i)
{
case ETB_COMMENT:
s1=file->comment;
if(s1==NULL)
{
*buffer++=0;
break;
}
bsize=commsize;
/* Fall through */
case ETB_NAME:
if(i==ETB_NAME)
{
s1=file->name;
bsize=namesize;
}
s2=(STRPTR)buf;
if(bsize)
{
/* Fixed sized field */
if(bsize/sizeof(ULONG)>siz)
return ERROR_BUFFER_OVERFLOW;
siz-=bsize/sizeof(ULONG)-1;
do
if(!(*s2++=*s1++))
break;
while(--bsize);
s2[-1]=0;
}else
/* Variable sized field */
for(;;)
{
for(k=0;k<sizeof(ULONG);k++)
if(!(*s2++=*s1++))
{
for(;k<sizeof(ULONG);k++)
*s2++=0;
break;
}
if(!--siz)
return ERROR_BUFFER_OVERFLOW;
}
buf=(ULONG*)s2;
break;
case ETB_TYPE:
*buf++=file->type;
break;
case ETB_PROTECT:
*buf++=file->protect;
break;
case ETB_SIZE:
*buf++=file->size;
break;
case ETB_DOSLIST:
case ETB_SIZEH:
case ETB_BLOCKSUSED:
case ETB_BLOCKSUSEDH:
case ETB_DAYS:
case ETB_MINUTES:
case ETB_TICKS:
case ETB_OWNERIDS:
case ETB_DISKSTATE:
case ETB_BYTESPERBLK:
case ETB_DISKTYPE:
*buf++=0;
break;
}
siz--;
}
type<<=1;
}
*buffer=buf;
*size=siz*sizeof(ULONG);
return 0;
}
static LONG examine(struct filehandle *handle, ULONG *buffer, ULONG size, struct TagItem *tags)
{
ULONG type[16], filesize=0, commsize=0;
while(tags->ti_Tag!=TAG_END)
{
switch(tags->ti_Tag)
{
case EXA_TYPE:
type=tags->ti_Data;
break;
case EXA_NAMESIZE:
filesize=tags->ti_Data;
break;
case EXA_COMMENTSIZE:
commsize=tags->ti_Data;
break;
default:
return ERROR_NOT_IMPLEMENTED;
}
tags++;
}
return examine_node((struct fnode *)handle->node, &buffer, &size, type, namesize, commsize);
}
#endif
static LONG delete_object(struct rambase *rambase, struct filehandle *filehandle, char *name)
{
struct fnode *file=(struct fnode *)filehandle->node;
if((struct fnode *)file->volume==file)
return ERROR_OBJECT_WRONG_TYPE;
if(file->usecount)
return ERROR_OBJECT_IN_USE;
if(!(file->protect&FIBF_DELETE))
return ERROR_DELETE_PROTECTED;
if(file->type==ST_USERDIR&&((struct dnode *)file)->list.mlh_Head->mln_Succ!=NULL)
return ERROR_DIRECTORY_NOT_EMPTY;
delete(rambase,file);
return 0;
}
LONG die(struct rambase *rambase, struct filehandle *handle)
{
struct cnode *dev;
struct vnode *vol;
struct dnode *dir;
struct fnode *file;
dev=(struct cnode *)handle->node;
free_lock(rambase,handle);
if(dev->type!=ST_LINKDIR||dev->self!=dev)
return ERROR_OBJECT_WRONG_TYPE;
vol=dev->volume;
if(vol->volcount)
return ERROR_OBJECT_IN_USE;
RemDosEntry(vol->doslist);
FreeDosEntry(vol->doslist);
RemDosEntry(dev->doslist);
FreeDosEntry(dev->doslist);
while(vol->list.mlh_Head->mln_Succ!=NULL)
{
dir=(struct dnode *)vol->list.mlh_Head;
if(dir->type==ST_USERDIR)
while((file=(struct fnode *)RemHead((struct List *)&dir->list))!=NULL)
AddTail((struct List *)&vol->list,(struct Node *)dir);
delete(rambase,(struct fnode *)dir);
}
Strfree(rambase,vol->name);
FreeMem(vol,sizeof(struct vnode));
Strfree(rambase,dev->name);
FreeMem(dev,sizeof(struct cnode));
rambase->unitcount--;
return 0;
}
void deventry(struct rambase *rambase)
{
struct IOFileSys *iofs;
LONG error=0;
/*
Init device port. AllocSignal() cannot fail because this is a
freshly created task with all signal bits still free.
*/
rambase->port->mp_SigBit=AllocSignal(-1);
rambase->port->mp_Flags=PA_SIGNAL;
/* Get and process the messages. */
for(;;)
{
while((iofs=(struct IOFileSys *)GetMsg(rambase->port))!=NULL)
{
switch(iofs->IOFS.io_Command)
{
case FSA_STARTUP:
/*
mount a new dos device (a new filesystem)
Unit *root; root handle on return
STRPTR name; device name without colon
struct TagItem *args; further arguments
*/
AddTail((struct List *)&rambase->waitdoslist,&iofs->IOFS.io_Message.mn_Node);
continue;
case FSA_DIE:
/*
Free the lock then try to dismount dos device
Unit *root; handle to device's root directory
*/
AddTail((struct List *)&rambase->waitdoslist,&iofs->IOFS.io_Message.mn_Node);
continue;
case FSA_LOCATE_OBJECT:
/*
get handle on a file or directory
Unit *current; current directory / new handle on return
STRPTR name; file- or directoryname
LONG mode; locking mode
LONG protect; protection flags if a new file is created
*/
error=locate_object(rambase,(struct filehandle **)&iofs->IOFS.io_Unit,
(STRPTR)iofs->io_Args[0], iofs->io_Args[1]);
break;
case FSA_READ:
/*
read a number of bytes from a file
Unit *current; filehandle
APTR buffer; data
LONG numbytes; number of bytes to read /
number of bytes read on return,
0 if there are no more bytes in the file
*/
error=read(rambase,(struct filehandle *)iofs->IOFS.io_Unit,
(APTR)iofs->io_Args[0], &iofs->io_Args[1]);
break;
case FSA_WRITE:
/*
write a number of bytes to a file
Unit *current; filehandle
APTR buffer; data
LONG numbytes; number of bytes to write /
number of bytes written on return
*/
error=write(rambase,(struct filehandle *)iofs->IOFS.io_Unit,
(APTR)iofs->io_Args[0], &iofs->io_Args[1]);
break;
case FSA_SEEK:
/*
set / read position in file
Unit *current; filehandle
LONG posh;
LONG posl; relative position /
old position on return
LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
OFFSET_END
*/
error=seek(rambase,(struct filehandle *)iofs->IOFS.io_Unit,
&iofs->io_Args[0], &iofs->io_Args[1], iofs->io_Args[2]);
break;
case FSA_FREE_LOCK:
/*
get rid of a handle
Unit *current; filehandle
*/
error=free_lock(rambase,(struct filehandle *)iofs->IOFS.io_Unit);
break;
#if 0
case FSA_EXAMINE:
/*
Get information about the current object
Unit *current; current object
ULONG *buffer; to be filled
ULONG size; size of the buffer
ULONG type; type of information to get
*/
error=examine((struct filehandle *)iofs->IOFS.io_Unit,
(ULONG *)iofs->io_Args[0], iofs->io_Args[1],
iofs->io_Args[2]);
break;
#endif
/*
FSA_DELETE_OBJECT - delete file or directory
Unit *current; current directory
STRPTR name; filename
FSA_MAKE_LINK
Unit *current; current directory, untouched by the handler
STRPTR name; filename
LONG target; target handle for hardlinks/target name for softlinks
LONG mode; !=0 softlink
FSA_CREATE_DIR
FSA_RENAME
FSA_SET_PROTECT
FSA_SET_OWNER
FSA_SET_DATE
FSA_READ_LINK
FSA_DISK_INFO
FSA_SERIALIZE_DISK
FSA_MORE_CACHE
FSA_WAIT_CHAR
FSA_INFO
FSA_FLUSH
FSA_SET_COMMENT
FSA_TIMER
FSA_INHIBIT
FSA_DISK_TYPE
FSA_DISK_CHANGE
FSA_SCREEN_MODE
FSA_READ_RETURN
FSA_WRITE_RETURN
FSA_SET_FILE_SIZE
LONG current;
LONG pos;
LONG mode;
FSA_WRITE_PROTECT
FSA_SAME_LOCK
FSA_CHANGE_SIGNAL
FSA_FORMAT
FSA_IS_FILESYSTEM
FSA_CHANGE_MODE
FSA_EXAMINE_ALL
FSA_EXAMINE_FH
FSA_ADD_NOTIFY
FSA_REMOVE_NOTIFY
FSA_EXAMINE_ALL_END
*/
}
iofs->io_DosError=error;
ReplyMsg(&iofs->IOFS.io_Message);
}
if(rambase->waitdoslist.mlh_Head->mln_Succ!=NULL)
{
if(!AttemptLockDosList(LDF_DEVICES|LDF_VOLUMES|LDF_WRITE))
Delay(TICKS_PER_SECOND/2);
else
{
while((iofs=(struct IOFileSys *)RemHead((struct List *)&rambase->waitdoslist))!=NULL)
{
if(iofs->IOFS.io_Command==FSA_STARTUP)
error=startup(rambase,(STRPTR)iofs->io_Args[0],
(struct TagItem *)iofs->io_Args[1]);
else
error=die(rambase,(struct filehandle *)iofs->IOFS.io_Unit);
iofs->io_DosError=error;
ReplyMsg(&iofs->IOFS.io_Message);
}
UnLockDosList(LDF_DEVICES|LDF_VOLUMES|LDF_WRITE);
}
}
#if 0
if(rambase->iofs!=NULL)
{
iofs=rambase->iofs;
if(iofs->IOFS.io_Message.mn_Node.ln_Type==NT_MESSAGE)
{
abort_notify(rambase,iofs);
iofs->io_DosError=ERROR_BREAK;
rambase->iofs=NULL;
ReplyMsg(&iofs->IOFS.io_Message);
}else
{
rambase->iofs=NULL;
Signal(1,0);
}
}
#endif
Wait(1<<rambase->port->mp_SigBit);
}
}
const char end=0;